/**
 * @author emylyano3
 */

package org.generic.download;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

public class DownloadManager implements Runnable {

	//**************************************************************************************************
	//	Attributes.
	//**************************************************************************************************
	
	private Vector listeners = new Vector();
	private String  url;
	private int id;
	private boolean isRunning = false;
	
	private Queue requestQueue;
	
	//**************************************************************************************************
	//	Constructor.
	//**************************************************************************************************
	
	public DownloadManager() {
		requestQueue = new Queue();
	}

	//**************************************************************************************************
	//	Public Methods.
	//**************************************************************************************************
	
	/**
	 * Creates a new thread that will manage the connection to the url passed as 
	 * parameter. When the download is finished, the object that made the download
	 * request will be noticed.
	 * @param url The url to which this method in going to connect.
	 * @param id The id of the resource.
	 * */
	public void download(DownloadRequest r) {
		if (!isRunning) {
			this.url = r.getUrl();
			this.id = r.getId();
			Thread t = new Thread(this);
			isRunning = true;
			t.start();
		} else {
			requestQueue.add(r);
		}
	}
	 
	public void run() {
		ByteArrayOutputStream buffer 	= null;
		HttpConnection connection  		= null;
		InputStream    inputStream 		= null;
		Enumeration    enumeration 		= null;
		try {
			buffer = new ByteArrayOutputStream();
			
			connection  = (HttpConnection) Connector.open(this.url);
			inputStream = connection.openInputStream();
			
			long length = connection.getLength();
			byte[] data = new byte[512];
			int total = 0x00;
			int read  = -1;
			do {
				read = inputStream.read(data);
				if (read > 0x00) {
					total += read;
					buffer.write(data, 0x00, read);
					enumeration = this.listeners.elements();
					while (enumeration.hasMoreElements()) {
						DownloadListener listener = (DownloadListener) enumeration.nextElement();
						listener.downloadStatus((int)(total * 100 / length), id);
					}
				}
			} while (read != -1);
		} catch (IOException e) {
			System.out.println("EMY ERROR 2");
			enumeration = this.listeners.elements();
			while (enumeration.hasMoreElements()) {
				DownloadListener listener = (DownloadListener) enumeration.nextElement();
				listener.downloadError(e);
			}
		} finally {
			enumeration = this.listeners.elements();
			while (enumeration.hasMoreElements()) {
				DownloadListener listener = (DownloadListener) enumeration.nextElement();
				listener.downloadCompleted(buffer.toByteArray(), id);
				isRunning = false;
				if (!requestQueue.isEmpty()) {
					download((DownloadRequest) requestQueue.poll());
				}
			}
			
			try {				
				inputStream.close();
				connection.close();
			} catch (Exception e) {
				System.out.println("EMY ERROR 1");
				enumeration = this.listeners.elements();
				while (enumeration.hasMoreElements()) {
					DownloadListener listener = (DownloadListener) enumeration.nextElement();
					listener.downloadError(e);
				}
			}
		}
	}

	/**
	 * Adds a listener for downloads.
	 * @param listener target listener.
	 */
	public void addListener(DownloadListener listener) {
		if (!this.listeners.contains(listener)) {			
			this.listeners.addElement(listener);
		}
	}
	
	/**
	 * Removes a listener for downloads.
	 * @param listener target listener.
	 */
	public void removeListener(DownloadListener listener) {
		this.listeners.removeElement(listener);
	}
	
	//**************************************************************************************************
	//	Private Methods.
	//**************************************************************************************************
	
	
	//**************************************************************************************************
	//	Inner Classes.
	//**************************************************************************************************
	
	protected class Queue extends Vector{
		
		public void add(Object o) {
			this.addElement(o);
		}
		
		public Object poll() {
			Object e;
			if (!this.isEmpty()) {
				e = this.elementAt(0);
				this.removeElementAt(0);
				return e;
			}
			return null;
		}
		
		public Object peek() {
			if (!this.isEmpty()) {
				return this.elementAt(0);
			}
			return null;
		}
	}
}
